using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Driver;
using Sustainalytics.CRT.Synchronization.Exception;

using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.ESG.Entities;
using WeightMatrix = Sustainalytics.Entities.ESGRatings.WeightMatrix;


namespace Sustainalytics.CRT.Synchronization
{

    public class FocusedRatingsCompanyScoreManager
    {
        private readonly IMongoCollection<CompanyWeights> companyWeightsCollection;

        private readonly IMongoCollection<RPIndicatorExtended> rawScoresCollection;
        private readonly IMongoCollection<EsgResearchProfile> esgResearchProfileCollection;

        private readonly FocusedRatingsCompanyScoreCalculator scoreCalculator;

        public FocusedRatingsCompanyScoreManager(string clientDw, FocusedRatingsCompanyScoreCalculator scoreCalculator)
        {
            this.scoreCalculator = scoreCalculator;
            companyWeightsCollection = MongoFactory.GetCollectionFromDatabase<CompanyWeights>(clientDw);
            rawScoresCollection = MongoFactory.GetCollectionFromDatabase<RPIndicatorExtended>(clientDw);
            esgResearchProfileCollection = MongoFactory.GetCollectionFromDatabase<EsgResearchProfile>(clientDw);
        }

        public async Task LoadCompanyScoreAsync(RPCompanyESGComputationResult computationResult)
        {
            var importedComputationResult = await esgResearchProfileCollection
                .Find(x => x.Id == computationResult.Id)
                .Project(x => new {
                    x.ComputationResult.OverallPerformance.Score,
                    x.ComputationResult.Indent,
                    ComputationIndicators = x.ComputationResult.Indicators,
                    Indicators = x.Indicators})
                .FirstOrDefaultAsync().ConfigureAwait(false);

            //TODO CRT: verify if this will ever throw
            if (importedComputationResult == null)
                throw new CompanyEsgComputationResultNotFoundException(computationResult.Id);

            var indicatorsDictionary = importedComputationResult.Indicators.ToDictionary(x => x.Number, x => x);
            computationResult.Indicators = importedComputationResult.ComputationIndicators
                .Select(i => new RPIndicatorPerformance
                {
                    Code = i.Code,
                    SelectedAnswer = indicatorsDictionary.TryGetValue(i.Code, out var indicator) ? indicator.SelectedAnswer : null,
                    RawScore = i.RawScore,
                    Weight = i.Weight,
                    WeightedScore = i.WeightedScore
                })
                .ToArray();

            computationResult.Indent = importedComputationResult.Indent;
            computationResult.OverallPerformance.Score = importedComputationResult.Score;
        }

        public class FocusedRatingsPerformance
        {
            public FocusedRatingsPerformance()
            {
                Indicators = new List<RPIndicatorPerformance>();
            }

            public List<RPIndicatorPerformance> Indicators { get; set; }

            public double WeightedScore { get; set; }
        }
    }
}